package lumis.portal.presentation.core;

import lumis.portal.PortalContext;
import lumis.portal.PortalException;
import lumis.portal.PortalRequestParameters;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.dao.DaoException;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.manager.ManagerFactoryInternal;
import lumis.portal.page.PageConfig;
import lumis.portal.page.PageWebResource;
import lumis.portal.presentation.PageDocType;
import lumis.portal.presentation.PortalModeUtil;
import lumis.portal.presentation.PresentationControllerHtml.DataPreviewMode;
import lumis.portal.presentation.layout.defaultlayout.BodyComponent;
import lumis.portal.presentation.layout.defaultlayout.HTMLRootComponent;
import lumis.portal.presentation.perspective.IPortalMode;
import lumis.portal.presentation.perspective.Perspective;
import lumis.portal.presentation.perspective.admin.AddInterfaceBehavior;
import lumis.portal.presentation.perspective.admin.IPortalStudioPageRenderer;
import lumis.portal.presentation.perspective.admin.MoveInterfaceBehavior;
import lumis.portal.presentation.perspective.admin.RemoveInterfaceBehavior;
import lumis.portal.presentation.perspective.admin.SaveHoldersLayoutBehavior;
import lumis.portal.transaction.ITransaction;
import lumis.portal.transaction.PortalTransactionFactory;
import lumis.portal.url.WebResourceDiscoveryFilter;
import lumis.portal.url.IURLManager.CreateStrategy;

import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.wicket.MarkupContainer;
import org.apache.wicket.markup.IMarkupCacheKeyProvider;
import org.apache.wicket.markup.IMarkupResourceStreamProvider;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.util.resource.IResourceStream;

/**
 * The Wicket page used for processing a layout file.
 *
 * @version $Revision: 13322 $ $Date: 2011-08-08 13:48:20 -0300 (Mon, 08 Aug 2011) $
 * @since 6.0.0
 */
public class LayoutFilePage extends WebPage implements IMarkupResourceStreamProvider, IMarkupCacheKeyProvider
{
	/**
	 * The attribute name where is expected to the {@link IPageRenderer} 
	 * instance be available in the request.
	 * @see #getPageRenderer()
	 * @since 6.0.0
	 */
	static final String ATTRIBUTE_PAGE_RENDERER = IPageRenderer.class.getName();
	
	/**
	 * Page renderer for this page. Lazily loaded during {@link #getPageRenderer()}.
	 * @since 6.0.0
	 */
	private transient IPageRenderer pageRenderer;

	/**
	 * The page web resource used for rendering the current page. Lazily
	 * loaded by {@link #getPageWebResource()}. Between
	 * requests, this attribute is recovered base on {@link #dynamicPath}.
	 * @since 6.0.0
	 */
	private transient PageWebResource pageWebResource;
	
	/**
	 * The dynamic path of the page being rendered. Used to reconstruct the 
	 * value for {@link #pageWebResource}.
	 * @since 6.0.0
	 */
	private String dynamicPath;
	
	/**
	 * DOCTYPE used in the current page.
	 * @since 6.0.0
	 */
	private PageDocType pageDocType;
	
	/**
	 * Mode of renderization of the current page. Lazily loaded by {@link #getPortalMode()}.
	 * @since 6.0.0
	 */
	private transient IPortalMode portalMode;

	/**
	 * MarkupResourceStreamProvider of the current page. Cached on detach for ajax calls.
	 * @since 6.0.0
	 */
	private IMarkupResourceStreamProvider markupResourceStreamProvider;
	
	/**
	 * CacheKey of the current page. Cached on detach for ajax calls.
	 * @since 6.0.0
	 */
	private String cacheKey;
	
	/**
	 * Safe Mode flag of the current page. Cached on detach for ajax calls.
	 * @since 6.0.0
	 */
	private Boolean safeMode;
	
	public IResourceStream getMarkupResourceStream(MarkupContainer container, Class<?> containerClass)
	{
		if(markupResourceStreamProvider == null)
		{
			markupResourceStreamProvider = getPageRenderer().getMarkupResourceStreamProvider(this); 
		}
		return markupResourceStreamProvider.getMarkupResourceStream(container, containerClass);
	}

	public IPortalMode getPortalMode() 
	{
		if(portalMode == null)
			portalMode = PortalModeUtil.getPortalMode(getWebRequestCycle().getWebRequest().getHttpServletRequest());

		return portalMode;
	}

	public String getCacheKey(MarkupContainer container, Class<?> containerClass)
	{
		if(cacheKey == null)
		{
			cacheKey = getPageRenderer().getMarkupCacheKey(this);
		}
		return cacheKey;
	}

	@Override
	protected void onBeforeRender()
	{
		getPageRenderer();
		
		if(Perspective.ADMIN.equals(getPortalMode().getPerspective()))
		{
			add(new RemoveInterfaceBehavior());
			add(new MoveInterfaceBehavior());
			add(new AddInterfaceBehavior());
			add(new SaveHoldersLayoutBehavior());
		}
		
		if (getLayoutFilePath() == null)
		{
			// add components required for the genericLayoutFileMarkup
			HTMLRootComponent htmlComponent = new HTMLRootComponent("layoutfile_html");
			add(htmlComponent);
			htmlComponent.add(new BodyComponent("layoutfile_body"));
			pageDocType = PortalContext.getDefaultPageDocType();
		}
		else
		{
			// obtain the pageDocType for the page based on the markup
			MarkupStream markupStream = getAssociatedMarkupStream(false);
			if (markupStream == null)
			{
				pageDocType = PageDocType.NONE;
			}
			else
			{
				IResourceStream pageMarkupResourceStream = markupStream.getResource();
				if (pageMarkupResourceStream instanceof LayoutFileMarkupResourceStream)
				{
					pageDocType = ((LayoutFileMarkupResourceStream)pageMarkupResourceStream).getPageDocType();
				}
				else
				{
					//logger.error("Page's resource stream is not a LayoutFileMarkupResourceStream (assuming doctype none): " + pageMarkupResourceStream);
					pageDocType = PageDocType.NONE;
				}
			}
		}
			
		super.onBeforeRender();
	}

	@Override
	protected void onDetach()
	{	
		if (pageRenderer != null)
		{
			dynamicPath = WebResourceDiscoveryFilter.getWebResource(getWebRequestCycle().getWebRequest().getHttpServletRequest()).getDynamicPath();
			markupResourceStreamProvider = pageRenderer.getMarkupResourceStreamProvider(this);
			cacheKey = pageRenderer.getMarkupCacheKey(this);
			safeMode = isSafeMode();
		}
		
		pageWebResource = null;
		pageRenderer = null;
		super.onDetach();
	}
	
	@Override
	public Locale getLocale()
	{
		return getPageWebResource().getLocale();
	}
	
	@Override
	protected void setHeaders(WebResponse response)
	{
		// Wicket by default sets headers for disabling cache.
		// Overriding so no header is set (keeping same behavior as previous
		// Lumis Portal versions).
	}
	
	public boolean isForSelenium()
	{
		return Boolean.getBoolean("lumis.portal.selenium");
	}
	
	public DataPreviewMode getDataPreviewMode()
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getDataPreviewMode();
		else
			return new DataPreviewMode();
	}

	public String getRootChannelId()
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getRootChannelId();
		else
		{
			PageConfig page = getPageWebResource().getPage();
			return getRootChannelId(page);
		}
	}
	
	public List<String> getParentChannelIds()
	{
		try 
		{
			return ManagerFactory.getChannelManager().getPathIds(SessionConfig.getCurrentSessionConfig(), getPageWebResource().getPage().getChannelId(), PortalTransactionFactory.getCurrentTransaction());
		} 
		catch (PortalException e) 
		{
			throw new RuntimeException(e);
		}
	}

	public PageDocType getPageDocType()
	{
		return pageDocType;
	}
	
	public boolean isSafeMode()
	{
		if(safeMode == null){
			if (Perspective.ADMIN.equals(getPortalMode().getPerspective())) 
			{
				safeMode = ((IPortalStudioPageRenderer)getPageRenderer()).isSafeMode();
			} 
			else
			{
				safeMode = false;
			}
		}
		return safeMode;
	}
	
	public String getHighlightInterfaceInst()
	{
		String highlightInterfaceInst = null;
		if (Perspective.USER.equals(getPortalMode().getPerspective()))
			highlightInterfaceInst = (String) getRequest().getParameter(PortalRequestParameters.PAGE_PARAMETER_HIGHLIGHT_INTERFACE_INST);
		
		return highlightInterfaceInst;
	}
	
	public String getLayoutFilePath()
	{
		String layoutFilePath = null;

		// never use layout file for runtime interface
		if (getPageWebResource().getRunTimeServiceInterfaceId() == null)
		{
			layoutFilePath = getPageWebResource().getPage().getLayoutFilePath();
			if (layoutFilePath != null)
				layoutFilePath = PortalContext.getDefinitionPath(layoutFilePath);
		}

		return layoutFilePath;
	}

	public PortalRequestParameters getParameters() 
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getParameters();
		else
			return new PortalRequestParameters(SessionConfig.getCurrentSessionConfig(), PortalTransactionFactory.getCurrentTransaction());
	}
	
	public String getExecutedProcessActionServiceInterfaceInstanceId() 
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getExecutedProcessActionServiceInterfaceInstanceId();
		else
			return null;
	}

	public Map<String, String[]> getMultiPartFormParameters() 
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getMultiPartFormParameters();
		else
			return null;
	}

	public String getMultiPartFormServiceInterfaceInstance() 
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getMultiPartFormServiceInterfaceInstance();
		else
			return null;
	}

	public String getGeneratorPageCacheId()
	{
		return getRequest().getParameter(PortalRequestParameters.PAGE_PARAMETER_FROM_PCM);
	}

	public String getPreviousParametersXmlString()
	{
		if(getPageRenderer() != null)
			return getPageRenderer().getPreviousParametersXmlString();
		else
			return "<allParameters></allParameters>";		
	}		

	public boolean isPrinting()
	{
		boolean isPrinting = false;
		if ("1".equals(getRequest().getParameter(PortalRequestParameters.PAGE_PARAMETER_PRINTING)))
			isPrinting = true;

		return isPrinting;
	}
	
	/**
	 * Returns the PageWebResource for this page.
	 * @return the pageWebResource.
	 * 
	 * @since 6.0.0
	 */
	public PageWebResource getPageWebResource()
	{
		if (pageWebResource == null)
		{
			if(getPageRenderer() != null)
			{
				pageWebResource = getPageRenderer().getWebResource();
			}else{
				try
				{
					ITransaction transaction = PortalTransactionFactory.createTransaction();
					try
					{
						transaction.begin();
						
						pageWebResource = (PageWebResource) ManagerFactoryInternal.getURLManager().getWebResourceByDynamicPath(dynamicPath, CreateStrategy.NEVER);
						
						transaction.commit();
					}
					finally
					{
						transaction.dispose();
					}
				}
				catch(PortalException e)
				{
					throw new RuntimeException(e);
				}
			}
		}
		return pageWebResource;	
	}

	/**
	 * Returns the page renderer for this page.
	 * @return the page renderer.
	 * @since 6.0.0
	 */
	public IPageRenderer getPageRenderer()
	{
		if (pageRenderer == null)
		{
			HttpServletRequest request = getWebRequestCycle().getWebRequest().getHttpServletRequest();
			pageRenderer = (IPageRenderer) request.getAttribute(ATTRIBUTE_PAGE_RENDERER);
		}
		return pageRenderer;
	}
	
	/**
	 * Returns the root channel id of the current page.
	 * @param page the page config.
	 * @return the root channel id.
	 * @since 6.0.0
	 */
	public static String getRootChannelId(PageConfig page)
	{
		ITransaction transaction = PortalTransactionFactory.createTransaction();
		try
		{
			transaction.begin();
			String rootChannelId;
			List<String> parentChannelIds = ManagerFactory.getChannelManager().getPathIds(SessionConfig.getCurrentSessionConfig(), page.getChannelId(), PortalTransactionFactory.getCurrentTransaction());
			rootChannelId = page.getChannelId();
			transaction.commit();
			if (parentChannelIds != null && !parentChannelIds.isEmpty())
				rootChannelId = parentChannelIds.get(0);

			return rootChannelId;
		}
		catch(PortalException e)
		{
			throw new RuntimeException(e);
		}
		finally
		{
			try
			{
				transaction.dispose();
			}
			catch (DaoException e)
			{
				throw new RuntimeException(e);
			}
		}
	}
}